package com.ccl.iot.privates;


import android.text.TextUtils;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.ccl.iot.IOTNetAPI;
import com.ccl.iot.IOTNetAPIEnum;
import com.ccl.iot.device.IOTComplexDevice;
import com.ccl.iot.device.IOTDevice;
import com.ccl.iot.device.IOTVirtualDevice;
import com.ccl.iot.managers.DeviceManager;
import com.ccl.iot.managers.MainManager;
import com.ccl.iot.managers.UserManager;
import com.ccl.iot.object.IOTInfoWithValue;
import com.ccl.iot.publics.Messager;
import com.ccl.iot.publics.ThreadPoolUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class InfoProcessor {

    public static final String INFO_PATH = MainManager.KDEFAULT_DATABASE_PATH + "info/";

    private static InfoProcessor mInstance;

    public static void init() {
        mInstance = new InfoProcessor();
    }

    public static InfoProcessor getInstance() {
        return mInstance;
    }

    private IOTNetAPI mNetAPI = IOTNetAPI.GetInstance();

    private long mLogonUser = 0;
    private int mLastUserInfosVersion = 0;
    private HashMap<Long, Integer> mDevicesInfoVersions;
    private HashMap<String, String> mUserInfos;
    private HashMap<String, Map<String, String>> mDevInfos;

    public InfoProcessor() {

        UserManager.GetDefaultManager().addUserEventListener(new UserManager.UserEventListener() {

            @Override
            public void onLoginEvent(boolean aCanceled) {
                long logonUser = UserManager.GetDefaultManager().getLogonUser();
                if (logonUser != IOTNetAPIEnum.KINVALID_USER_ID && logonUser != mLogonUser) {
                    mLogonUser = logonUser;
                    initData();
                }
            }

            @Override
            public void onPrepareLogout() {
            }

            @Override
            public void onLogout(boolean aOK) {
                Log.e("InfoProcessor", "onLogout");
                mLastUserInfosVersion = -1;
                mDevicesInfoVersions.clear();
                mUserInfos.clear();
                mDevInfos.clear();
            }
        });
        mLogonUser = UserManager.GetDefaultManager().getLogonUser();
        if (mLogonUser != IOTNetAPIEnum.KINVALID_USER_ID) {
            initData();
        } else {
            mDevicesInfoVersions = new HashMap<>();
            mUserInfos = new HashMap<>();
            mDevInfos = new HashMap<>();
        }
    }

    private void initData() {
        mDevicesInfoVersions = new HashMap<>();
        FileInputStream fis = null;
        File file = new File(INFO_PATH + mLogonUser + "/uinfo.json");
        if (file.exists() && file.isFile()) {
            try {
                fis = new FileInputStream(file);
                byte[] buff = new byte[1024 * 10];
                int len;
                StringBuffer sb = new StringBuffer();
                while ((len = fis.read(buff)) > 0) {
                    sb.append(new String(buff, 0, len));
                }
                String infos = sb.toString();
                if (!TextUtils.isEmpty(infos)) {
                    mUserInfos = JSON.parseObject(infos, HashMap.class);
                } else {
                    mUserInfos = new HashMap<>();
                }
            } catch (Exception e) {
                mUserInfos = new HashMap<>();
                e.printStackTrace();
            } finally {
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            mUserInfos = new HashMap<>();
        }

        file = new File(INFO_PATH + mLogonUser + "/dinfo.json");
        if (file.exists() && file.isFile()) {
            try {
                fis = new FileInputStream(file);
                byte[] buff = new byte[1024 * 10];
                int len;
                StringBuffer sb = new StringBuffer();
                while ((len = fis.read(buff)) > 0) {
                    sb.append(new String(buff, 0, len));
                }
                String infos = sb.toString();
                if (!TextUtils.isEmpty(infos)) {
                    mDevInfos = JSON.parseObject(infos, HashMap.class);
                } else {
                    mDevInfos = new HashMap<>();
                }
            } catch (Exception e) {
                mDevInfos = new HashMap<>();
                e.printStackTrace();
            } finally {
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } else {
            mDevInfos = new HashMap<>();
        }
    }

    public String getInfo(long id, String key, boolean isOwner) {
        String result = null;
        if (isOwner) {
            Map<String, String> devInfo = mDevInfos.get(id + "");
            if (devInfo != null && devInfo.size() > 0) {
                result = devInfo.get(key);
                //                Log.e("getInfo", "isOwner id: " + id + ", key: " + key + ", value: " + result);
            }
        } else {
            result = mUserInfos.get(key);
            if (result == null) {
                Map<String, String> devInfo = mDevInfos.get(id + "");
                if (devInfo != null && devInfo.size() > 0) {
                    try {
                        String s = key.substring(0, 2) + (key.substring(key.indexOf('.')));
                        result = devInfo.get(s);
                    } catch (Exception e) {

                    }
                }
            }
        }
        return result;
    }

    public void changeDevInfo(final long id, final String key, final String value, final String oldValue) {
        Log.e("InfoChange", "changeDevInfo  id: " + id + ", key: " + key + ", value: " + value + ", oldValue: " + oldValue);
        boolean isNew = true;
        Map<String, String> devInfo = mDevInfos.get(id + "");
        if (devInfo == null) {
            devInfo = new HashMap<>();
            mDevInfos.put(id + "", devInfo);
        } else if (devInfo.containsKey(key)) {
            isNew = false;
        }
        devInfo.put(key, value);

        final boolean finalIsNew = isNew;
        ThreadPoolUtils.getInstance().addTask(new Runnable() {
            @Override
            public void run() {
                int count = 0;
                if (finalIsNew) {
                    while (count < 3) {
                        if (mNetAPI.addDeviceInfo(id, key, value)) {
                            return;
                        }
                        count++;
                    }
                } else {
                    while (count < 3) {
                        if (mNetAPI.editDeviceInfo(id, key, value)) {
                            return;
                        }
                        count++;
                    }
                }

                Map<String, String> devInfo = mDevInfos.get(id + "");
                if (devInfo != null) {
                    if (finalIsNew) {
                        devInfo.remove(key);
                        onDevInfoChange(id, key, oldValue);
                    } else {
                        devInfo.put(key, oldValue);
                        onDevInfoChange(id, key, oldValue);
                    }
                }
                Messager.Show("修改失败");
            }
        });
    }

    public void changeUserInfo(final String key, final String value, final String oldValue) {
        Log.e("InfoChange", "changeUserInfo  key: " + key + ", value: " + value + ", oldValue: " + oldValue);
        final boolean isNew = mUserInfos.containsKey(key) ? false : true;
        mUserInfos.put(key, value);
        ThreadPoolUtils.getInstance().addTask(new Runnable() {
            @Override
            public void run() {
                int count = 0;
                if (isNew) {
                    while (count < 3) {
                        if (mNetAPI.addPublicUserInfo(key, value)) {
                            return;
                        }
                        count++;
                    }
                } else {
                    while (count < 3) {
                        if (mNetAPI.editPublicUserInfo(key, value)) {
                            return;
                        }
                        count++;
                    }
                }

                if (isNew) {
                    mUserInfos.remove(key);
                    onUserInfoChange(key, oldValue);
                } else {
                    mUserInfos.put(key, oldValue);
                    onUserInfoChange(key, oldValue);
                }
                Messager.Show("修改失败");
            }
        });
    }

    public void updataAllInfos() {
        boolean userInfoChange = getAllUserInfos();
        ArrayList<IOTDevice> list = DeviceManager.GetDefaultManager().getList();
        if (list != null) {
            ArrayList<Long> ids = new ArrayList<Long>();
            for (IOTDevice dev : list) {
                if (!(dev instanceof IOTVirtualDevice)) {
                    long id = Math.abs(dev.getID());
                    if (!ids.contains(id)) {
                        ids.add(id);
                    }
                }
            }

            long[] idsParam = new long[ids.size()];
            for (int i = 0; i < idsParam.length; i++) {
                idsParam[i] = ids.get(i);
            }
            boolean devicesInfoChange = getDevicesInfos(idsParam);
            if (devicesInfoChange || userInfoChange) {
                saveAllInfo();
            }
        }
    }

    public boolean getAllUserInfos() {
        boolean isChange = false;
        int userInfoVersion = mNetAPI.getUserInfoVersion();
        if (userInfoVersion != mLastUserInfosVersion) {
            mLastUserInfosVersion = userInfoVersion;
            ArrayList<IOTInfoWithValue> publicUserInfoList = mNetAPI.getPublicUserInfoList();
            if (publicUserInfoList != null && publicUserInfoList.size() > 0) {
                for (IOTInfoWithValue info : publicUserInfoList) {
                    if (info != null) {
                        String name = info.getName();
                        String value = info.getValue();
                        String oldValue = mUserInfos.get(name);
                        if (oldValue == null || !oldValue.equals(value)) {
                            mUserInfos.put(name, value);
                            isChange = true;
                            onUserInfoChange(name, value);
                        }
                    }
                }
            }
        }
        return isChange;
    }

    public boolean getDevicesInfos(long[] ids) {
        boolean isChange = false;
        if (ids != null && ids.length > 0) {
            int befor = 0;
            int after = ids.length;
            if (after > 16) {
                after = 16;
            }
            while (after != befor) {
                long[] slipIds = Arrays.copyOfRange(ids, befor, after);
                int[] vers = new int[slipIds.length];
                int verListResult = mNetAPI.getDeviceInfoVersionList(slipIds, vers);
                if (verListResult == 0) {
                    for (int i = 0; i < slipIds.length; i++) {
                        Integer integer = mDevicesInfoVersions.get(slipIds[i]);
                        if (integer == null || integer != vers[i]) {
                            mDevicesInfoVersions.put(slipIds[i], vers[i]);
                            Map<String, String> devInfo = mDevInfos.get(slipIds[i] + "");
                            if (devInfo == null) {
                                devInfo = new HashMap<>();
                                mDevInfos.put(slipIds[i] + "", devInfo);
                            }
                            ArrayList<IOTInfoWithValue> deviceInfoList = mNetAPI.getDeviceInfoList(slipIds[i]);
                            if (deviceInfoList != null && deviceInfoList.size() > 0) {
                                for (IOTInfoWithValue info : deviceInfoList) {
                                    if (info != null) {
                                        String name = info.getName();
                                        String value = info.getValue();
                                        String oldValue = devInfo.get(name);
                                        if (oldValue == null || !oldValue.equals(value)) {
                                            devInfo.put(name, value);
                                            isChange = true;
                                            onDevInfoChange(slipIds[i], name, value);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                befor = after;
                after += 16;
                if (after > ids.length) {
                    after = ids.length;
                }
            }
        }
        return isChange;
    }

    private void onUserInfoChange(String key, String value) {
        //        Log.e("getInfo", "onUserInfoChange key: " + key + ", value: " + value);
        if (!TextUtils.isEmpty(key)) {
            int index = key.indexOf('.');
            if (index > 2) {
                long devId = mNetAPI.GetLongID(key.substring(2, index));
                IOTDevice device = DeviceManager.GetDefaultManager().findDevice(devId);
                if (device != null) {
                    index = (int) mNetAPI.GetLongID(key.substring(index));
                    if (device instanceof IOTComplexDevice) {
                        index--;
                        IOTDevice[] devices = ((IOTComplexDevice) device).getDevices();
                        if (devices != null && devices.length > index) {
                            if (key.startsWith(IOTDevice.KIOT_DEVICE_NAME_LABEL)) {
                                devices[index].updateName(value);
                            } else if (key.startsWith(IOTDevice.KIOT_DEVICE_ICON_LABEL)) {
                                devices[index].updateIcon(value);
                            }
                        }
                    } else {
                        if (index == 1) {
                            if (key.startsWith(IOTDevice.KIOT_DEVICE_NAME_LABEL)) {
                                device.updateName(value);
                            } else if (key.startsWith(IOTDevice.KIOT_DEVICE_ICON_LABEL)) {
                                device.updateIcon(value);
                            }
                        }
                    }
                }
            }
        }
    }

    private void onDevInfoChange(long id, String key, String value) {
        //        Log.e("getInfo", "onDevInfoChange "+", id: "+id+", key: " + key + ", value: " + value);
        if (!TextUtils.isEmpty(key)) {
            int index = key.indexOf('.');
            if (index == 2) {
                IOTDevice device = DeviceManager.GetDefaultManager().findDevice(id);
                if (device != null) {
                    index = (int) mNetAPI.GetLongID(key.substring(index));
                    if (device instanceof IOTComplexDevice) {
                        index--;
                        IOTDevice[] devices = ((IOTComplexDevice) device).getDevices();
                        //                        Log.e("InfoChange", "key: " + key + ", value: " + value + ", index: " + index+", len: "+devices.length);
                        if (index >= 0 && devices != null && devices.length > index) {
                            if (key.startsWith(IOTDevice.KIOT_DEVICE_NAME_LABEL)) {
                                if (!devices[index].isOwner()) {
                                    if (mUserInfos.get(devices[index].getNameLabel()) != null) {
                                        return;
                                    }
                                }
                                devices[index].updateName(value);
                            } else if (key.startsWith(IOTDevice.KIOT_DEVICE_ICON_LABEL)) {
                                if (!devices[index].isOwner()) {
                                    if (mUserInfos.get(devices[index].getIconLabel()) != null) {
                                        return;
                                    }
                                }
                                devices[index].updateIcon(value);
                            }
                        }
                    } else {
                        if (index == 1) {
                            if (key.startsWith(IOTDevice.KIOT_DEVICE_NAME_LABEL)) {
                                if (!device.isOwner()) {
                                    if (mUserInfos.get(device.getNameLabel()) != null) {
                                        return;
                                    }
                                }
                                device.updateName(value);
                            } else if (key.startsWith(IOTDevice.KIOT_DEVICE_ICON_LABEL)) {
                                if (!device.isOwner()) {
                                    if (mUserInfos.get(device.getIconLabel()) != null) {
                                        return;
                                    }
                                }
                                device.updateIcon(value);
                            }
                        }
                    }
                }
            }
        }
    }

    public void saveAllInfo() {
        String s = JSON.toJSONString(mUserInfos);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(new File(INFO_PATH + mLogonUser + "/uinfo.json"));
            fos.write(s.getBytes());
            fos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        s = JSON.toJSONString(mDevInfos);
        fos = null;
        try {
            fos = new FileOutputStream(new File(INFO_PATH + mLogonUser + "/dinfo.json"));
            fos.write(s.getBytes());
            fos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
